package jmind.core.image.code;

import jmind.base.lang.Pair;
import jmind.base.util.RandUtil;
import jmind.core.image.ImageUtil;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;

/**
 * https://jjjssh.iteye.com/blog/2422844
 * 根据源图片，剪切出两张图
 *
 * @author weibo
 * @date 2019/07/16
 */
public class ImageValidateCode {

    private static Color getRandColor(int fc, int bc) {//给定范围获得随机颜色
        if (fc > 255) fc = 255;
        if (bc > 255) bc = 255;
        int r = fc + RandUtil.nextInt(bc - fc);
        int g = fc + RandUtil.nextInt(bc - fc);
        int b = fc + RandUtil.nextInt(bc - fc);
        return new Color(r, g, b);

    }

    /**
     * 早年生成验证码
     *
     * @return
     */
    public static Pair<String, BufferedImage> getImageCode() {
        String sRand = RandUtil.randomCode(6);
        return Pair.of(sRand, createImage(sRand));
    }

    public static BufferedImage createImage(String sRand) {
        // 在内存中创建图象
        int width = 82, height = 20;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 获取图形上下文
        Graphics g = image.getGraphics();
        // 设定背景色
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height);
        //设定字体
        g.setFont(new Font("Dialog", Font.BOLD, 16));
        //画边框
        //g.setColor(new Color());
        //g.drawRect(0,0,width-1,height-1);
        // 随机产生155条干扰线，使图象中的认证码不易被其它程序探测到
        g.setColor(getRandColor(160, 200));
        for (int i = 0; i < 155; i++) {

            int x = RandUtil.nextInt(width);
            int y = RandUtil.nextInt(height);
            int xl = RandUtil.nextInt(12);
            int yl = RandUtil.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);

        }
        // 取随机产生的认证码(6个字符)
        for (int i = 0; i < sRand.length(); i++) {
            // 将认证码显示到图象中
            g.setColor(new Color(20 + RandUtil.nextInt(110), 20 + RandUtil.nextInt(110),
                    20 + RandUtil.nextInt(110))); //调用函数出来的颜色相同，可能是因为种子太接近，所以只能直接生成
            g.drawString(String.valueOf(sRand.charAt(i)), 13 * i + 6, 16 + RandUtil.nextInt(3));
        }
        g.dispose();
        return image;

    }


    /**
     * @param width           宽
     * @param height          高
     * @param interferingLine 干扰线
     * @return
     * @throws IOException
     */
    public static  BufferedImage getVerifyImg(int width, int height, String code , int interferingLine)  {

        int fontHeight = height / 2;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics graphic = image.getGraphics();
        graphic.setColor(Color.getColor("F8F8F8"));
        graphic.fillRect(0, 0, width, height);

        Color[] colors = new Color[]{Color.BLUE, Color.GRAY, Color.GREEN, Color.RED, Color.BLACK, Color.ORANGE,
                Color.CYAN};
        // 在 "画板"上生成干扰线条 ( 50 是线条个数)
        for (int i = 0; i < interferingLine; i++) {
            graphic.setColor(colors[RandUtil.nextInt(colors.length)]);
            final int x = RandUtil.nextInt(width);
            final int y = RandUtil.nextInt(height);
            final int w = RandUtil.nextInt(20);
            final int h = RandUtil.nextInt(20);
            final int signA = RandUtil.randomBoolean() ? 1 : -1;
            final int signB = RandUtil.randomBoolean() ? 1 : -1;
            graphic.drawLine(x, y, x + w * signA, y + h * signB);
        }

        // 在 "画板"上绘制字母
        graphic.setFont(new Font("Comic Sans MS", Font.BOLD, fontHeight));
        for (int i = 0; i < code.length(); i++) {
            graphic.setColor(colors[RandUtil.nextInt(colors.length)]);
          //  graphic.drawString(String.valueOf(code.charAt(i)), i * (width / 6), height - (height / 3));
            graphic.drawString(String.valueOf(code.charAt(i)), 13 * i + 5, 16 + RandUtil.nextInt(4));
        }
        graphic.dispose();
        //ByteArrayOutputStream os = new ByteArrayOutputStream();
        //ImageIO.write(image, "png", os);
        //byte b[] = os.toByteArray();
        return image;
    }

    /**
     * 根据原图生成一张裁剪图
     *
     * @param x          裁剪位置x轴
     * @param y          裁剪位置y轴
     * @param width      裁剪图片宽
     * @param height     裁剪图片高
     * @param sourceFile 原图
     * @param targetFile 生成的新的裁剪图
     * @throws IOException
     */
    public static File cut(int x, int y, int width, int height, String sourceFile, String targetFile) throws IOException {//裁剪方法
        FileInputStream is = null;
        ImageInputStream iis = null;
        try {
            //读取原始图片
            is = new FileInputStream(sourceFile);
            //ImageReader声称能够解码指定格式
            Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = it.next();
            //获取图片流
            iis = ImageIO.createImageInputStream(is);
            //将iis标记为true（只向前搜索）意味着包含在输入源中的图像将只按顺序读取
            reader.setInput(iis, true);
            //指定如何在输入时从 Java Image I/O框架的上下文中的流转换一幅图像或一组图像
            ImageReadParam param = reader.getDefaultReadParam();
            //定义空间中的一个区域
            Rectangle rect = new Rectangle(x, y, width, height);
            //提供一个 BufferedImage，将其用作解码像素数据的目标。
            param.setSourceRegion(rect);
            //读取索引imageIndex指定的对象
            BufferedImage bi = reader.read(0, param);
            //保存新图片
            File file = new File(targetFile);
            ImageIO.write(bi, "png", new File(targetFile));
            return file;
        } finally {
            if (is != null) {
                is.close();
            }
            if (iis != null) {
                iis.close();
            }
        }
    }

    /**
     * 随机生成一张移动的小图和 遮罩的图
     *
     * @param width      裁剪图片宽
     * @param height     裁剪图片高
     * @param sourceFile 原图
     * @return
     * @throws IOException
     */
    public static ImageCode cutByTemplate(String sourceFile, int width, int height) throws IOException {
        //原图
        BufferedImage oriImage = ImageIO.read(new File(sourceFile));
        //移动图,小图
        BufferedImage newSrc = new BufferedImage(oriImage.getWidth(), oriImage.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
        //对比图 ，带遮罩的原图
        BufferedImage newSrc2 = new BufferedImage(oriImage.getWidth(), oriImage.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
        int border = 20;
        //10,width-200
        int x = RandUtil.nextInt(oriImage.getWidth() - width - border) + border;

        int y = RandUtil.nextInt(oriImage.getHeight() - height - border) + border;
        //固定圆半径为5
        int c_r = 20;
        //r平方
        double rr = Math.pow(c_r, 2);
        //圆心的位置

        //x+c_r+10;//圆心x坐标必须在(x+r,x+with-r)范围内
        int c_a = RandUtil.nextInt(width - 2 * c_r) + (x + c_r);
        int c_b = y;

        //第二个圆（排除圆内的点）

        int c2_a = x;
        //y+c_r+50;//圆心y坐标必须在(y+r,y+height-r)范围内
        int c2_b = RandUtil.nextInt(height - 2 * c_r) + (y + c_r);

        for (int i = 0; i < oriImage.getWidth(); i++) {
            for (int j = 0; j < oriImage.getHeight(); j++) {
                //(x-a)²+(y-b)²=r²中，有三个参数a、b、r，即圆心坐标为(a，b)，半径r。
                double f = Math.pow((i - c_a), 2) + Math.pow((j - c_b), 2);

                double f2 = Math.pow((i - c2_a), 2) + Math.pow((j - c2_b), 2);

                int rgb = oriImage.getRGB(i, j);
                //在矩形内
                if (i >= x && i < (x + width) && j >= y && j < (y + height) && f2 >= rr) {
                    //块范围内的值
                    in(newSrc, newSrc2, i, j, rgb);
                } else if (f <= rr) {
                    //在圆内
                    in(newSrc, newSrc2, i, j, rgb);
                } else {
                    //剩余位置设置成透明
                    out(newSrc, newSrc2, i, j, rgb);
                }

            }
        }
        ImageCode imageCode = new ImageCode();
        imageCode.setX(x);
        imageCode.setY(y);
        imageCode.setTemplateImage(newSrc);
        imageCode.setTargetImage(newSrc2);
        return imageCode;
    }

    private static void in(BufferedImage newSrc, BufferedImage newSrc2, int i, int j, int rgb) {
        newSrc.setRGB(i, j, rgb);
        //原图设置变灰
        int r = (0xff & rgb);
        int g = (0xff & (rgb >> 8));
        int b = (0xff & (rgb >> 16));
        rgb = r + (g << 8) + (b << 16) + (100 << 24);
        //rgb = r + (g << 8) + (b << 16);
        newSrc2.setRGB(i, j, rgb);
    }

    private static void out(BufferedImage newSrc, BufferedImage newSrc2, int i, int j, int rgb) {
        newSrc.setRGB(i, j, 0x00ffffff);
        newSrc2.setRGB(i, j, rgb);
    }


    public static void main(String[] args) throws Exception {


        //int blockWidth=100;
        //int blockHeight=100;
        //ImageCode imageCode = cutByTemplate("/Users/weibo/Downloads/vcode/2.jpg", blockWidth,
        //    blockHeight );//图片大小是固定，位置是随机
        //
        ////生成移动图
        //ImageIO.write(imageCode.getTemplateImage(), "png", new File("/Users/weibo/Downloads/vcode/v3.png"));
        ////生成对比图
        //ImageIO.write(imageCode.getTargetImage(), "png", new File("/Users/weibo/Downloads/vcode/v4.png"));



//        Pair<String,BufferedImage> verifyImg = getImageCode();
//
//        ImageUtil.write(verifyImg.getSecond(), "png", "/Users/weibo/Downloads/vcode/a2.png");
//        System.err.println(verifyImg.getFirst());

        Pair<String, Integer> vCode = RandUtil.mathVCode();
        BufferedImage image= ImageValidateCode.getVerifyImg(89,32,vCode.getFirst(),20);
        System.err.println(vCode);
        ImageUtil.write(image, "png", "/Users/weibo/Downloads/vcode/a3.png");

    }
}
